package com.changzhi.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.changzhi.common.constans.Constants;
import com.changzhi.common.constans.RedisConstans;
import com.changzhi.common.exception.ServiceException;
import com.changzhi.common.util.DateUtil;
import com.changzhi.ldyl.model.*;
import com.changzhi.ldyl.model.vo.TaskVo;
import com.changzhi.ldyl.model.vo.UserVo;
import com.changzhi.mapper.ActivityDataMapper;
import com.changzhi.mapper.ActivityPrizeMapper;
import com.changzhi.mapper.ActivityRecordMapper;
import com.changzhi.mapper.ActivityWalletMapper;
import com.changzhi.service.*;
import com.changzhi.util.CommonUtil;
import com.changzhi.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Description:
 * @author: 小落
 * @date: 2021年05月21日
 */
@Slf4j
@Service
public class SignServiceImpl implements SignService {

	@Autowired
	private ActivityService activityService;
	@Autowired
	private UserService userService;
	@Autowired
	private RedisUtil redisUtil;
	@Resource
	private ActivityRecordMapper activityRecordMapper;
	@Autowired
	private GiftService giftService;
	@Resource
	private ActivityWalletMapper activityWalletMapper;
	@Autowired
	private ActivityPrizeMapper activityPrizeMapper;
	@Autowired
	private ActivityDataMapper activityDataMapper;

	public static Map<String, LocalDateTime> TIME_MAP = new HashMap<>();
	public static Map<Integer, ActivityPrize> GIFT_MAP = new HashMap<>();
	public final static Integer ACTIVITY_ID = 16;
	private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

	@PostConstruct
	public void init(){
		redisUtil.del(RedisConstans.ACTIVITY + ACTIVITY_ID);
		Activity activity2 = activityService.getActivity(ACTIVITY_ID);
		List<ActivityPrize> allPrizeList = activityService.getPrizeList(ACTIVITY_ID, null);
		//存指定礼物
		List<ActivityPrize> somePrizeList = allPrizeList.stream().filter(p -> p.getType() < 10).collect(Collectors.toList());
		for (ActivityPrize activityPrize : somePrizeList) {
			GIFT_MAP.put(activityPrize.getGiftId(), activityPrize);
		}
		//存活动时间
		TIME_MAP.put("startTime", activity2.getStartTime());
		TIME_MAP.put("endTime", activity2.getEndTime());
	}

	//是否指定礼物
	private boolean isPointPrize(Integer giftId){
		Integer result = (Integer) redisUtil.hget(RedisConstans.SIGN_POINT_GIFT  + "_" + ACTIVITY_ID, giftId.toString());
		if(result == null){
			LambdaQueryWrapper<ActivityPrize> wrapper = new LambdaQueryWrapper<>();
			wrapper.select(ActivityPrize::getId);
			wrapper.eq(ActivityPrize::getActivityId, ACTIVITY_ID).eq(ActivityPrize::getStatus, 1).eq(ActivityPrize::getGiftId, giftId).lt(ActivityPrize::getType, 10).last("limit 1");
			if(activityPrizeMapper.selectOne(wrapper) == null){
				result = 0;
			} else {
				result = 1;
			}
			redisUtil.hset(RedisConstans.SIGN_POINT_GIFT + "_" + ACTIVITY_ID, giftId.toString(), result, RedisConstans.ONE_WEEK);
		}
		if(result == 1){
			return true;
		}
		return false;
	}

	@Override
	public void doMqDataByUserGift(UserGift userGift) {
		//1.是否在活动时间内
		if(!DateUtil.isBetweenTime(TIME_MAP.get("startTime"), TIME_MAP.get("endTime"))){
			//测试账号通行
			if(!CommonUtil.getTestAccountList().contains(userGift.getUserId())){
				return;
			}
		}
		//2.指定礼物
		if(!isPointPrize(userGift.getGiftId())){
			return;
		}
		String userId = userGift.getUserId();
		String targetId = userGift.getTargetId();
		Integer value = userGift.getTotalGiftValue() * 10;
		//3.插入记录
		ActivityRecord activityRecord = new ActivityRecord();
		activityRecord.setActivityId(ACTIVITY_ID);
		activityRecord.setType(0);
		activityRecord.setUserId(userId);
		activityRecord.setTargetUserId(targetId);
		activityRecord.setValue(value);
		activityRecord.setNum(userGift.getGiftCount());
		activityRecord.setGiftId(userGift.getGiftId());
		activityRecordMapper.insert(activityRecord);
		//4.增加送礼用户礼物值
		String key1 = RedisConstans.putRediskey(RedisConstans.ACTIVITY_FLAG, ACTIVITY_ID, userId);
		Integer id = redisUtil.get(key1);
		if (id == null) {
			LambdaQueryWrapper<ActivityWallet> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(ActivityWallet::getActivityId, ACTIVITY_ID).eq(ActivityWallet::getUserId, userId).last("limit 1");
			ActivityWallet activityWallet = activityWalletMapper.selectOne(wrapper);
			if(activityWallet != null){
				activityWalletMapper.addAmount1(activityWallet.getId(), value);
				redisUtil.set(key1, activityWallet.getId(), RedisConstans.TWO_MONTH);
			} else {
				ActivityWallet record = new ActivityWallet();
				record.setActivityId(ACTIVITY_ID);
				record.setUserId(userId);
				record.setAmount1(value);
				activityWalletMapper.insert(record);
				redisUtil.set(key1, record.getId(), RedisConstans.TWO_MONTH);
			}
		} else{
			activityWalletMapper.addAmount1(id, value);
		}
		//5.增加收礼用户礼物值
		String key2 = RedisConstans.putRediskey(RedisConstans.ACTIVITY_FLAG, ACTIVITY_ID, targetId);
		Integer id2 = redisUtil.get(key2);
		if (id2 == null) {
			LambdaQueryWrapper<ActivityWallet> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(ActivityWallet::getActivityId, ACTIVITY_ID).eq(ActivityWallet::getUserId, targetId).last("limit 1");
			ActivityWallet activityWallet = activityWalletMapper.selectOne(wrapper);
			if(activityWallet != null){
				activityWalletMapper.addAmount2(activityWallet.getId(), value);
				redisUtil.set(key2, activityWallet.getId(), RedisConstans.TWO_MONTH);
			} else {
				ActivityWallet record = new ActivityWallet();
				record.setActivityId(ACTIVITY_ID);
				record.setUserId(targetId);
				record.setAmount2(value);
				activityWalletMapper.insert(record);
				redisUtil.set(key2, record.getId(), RedisConstans.TWO_MONTH);
			}
		} else{
			activityWalletMapper.addAmount2(id2, value);
		}
		//
		executorService.schedule(()->{
			try {
				//6.删除钱包缓存
				redisUtil.del(RedisConstans.putRediskey(RedisConstans.WALLET, ACTIVITY_ID, userId));
				redisUtil.del(RedisConstans.putRediskey(RedisConstans.WALLET, ACTIVITY_ID, targetId));
				//7.重新获取排行榜
				getRankingsByDb(null);
				//8.发放达到要求的奖励
				ActivityWallet wallet1 = activityWalletMapper.getWalletByUserId(ACTIVITY_ID, userId);
				//任务奖品
				List<ActivityPrize> prizeList = getPrize(1);
				if(wallet1 != null){
					Integer value1 = wallet1.getAmount1() > wallet1.getAmount2() ? wallet1.getAmount1() : wallet1.getAmount2();
					giveReward(userId, value1, prizeList);
				}
				ActivityWallet wallet2 = activityWalletMapper.getWalletByUserId(ACTIVITY_ID, targetId);
				if(wallet2 != null){
					Integer value2 = wallet2.getAmount1() > wallet2.getAmount2() ? wallet2.getAmount1() : wallet2.getAmount2();
					giveReward(targetId, value2, prizeList);
				}
			} catch(Exception e) {
				e.printStackTrace();
				log.error("methodName:doMqDataByUserGift,sign,error={}", e.getMessage());
			}
		}, 1, TimeUnit.SECONDS);;
	}

	/**
	 * 奖品：0=指定礼物，1=任务奖品，2=排行榜奖品
	 * @param type
	 * @return
	 */
	private List<ActivityPrize> getPrize(Integer type){
		List<ActivityPrize> list = (List<ActivityPrize>) redisUtil.hget(RedisConstans.SIGN_PRIZE + ACTIVITY_ID, type.toString());
		if(!CollectionUtils.isEmpty(list)){
			return list;
		}
		LambdaQueryWrapper<ActivityPrize> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(ActivityPrize::getActivityId, ACTIVITY_ID).eq(ActivityPrize::getStatus, 1);
		if(type == 0){
			wrapper.lt(ActivityPrize::getType, 10);
		} else if(type == 1){
			wrapper.ge(ActivityPrize::getType, 10).lt(ActivityPrize::getType, 100);
		} else {
			wrapper.ge(ActivityPrize::getType, 100);
		}
		list = activityPrizeMapper.selectList(wrapper);
		redisUtil.hset(RedisConstans.SIGN_PRIZE + ACTIVITY_ID, type.toString(), list, RedisConstans.ONE_WEEK);
		return list;
	}


	private List<UserVo> getRankingsByDb(Integer type){
		if(type == null){
			List<UserVo> list2 = activityWalletMapper.selectValue2Rankings(ACTIVITY_ID, 50);
			setDefaultAvatar(list2);
			redisUtil.set(RedisConstans.putRediskey(RedisConstans.RANKING, ACTIVITY_ID, 1), list2, RedisConstans.ONE_DAY);
			List<UserVo> list = activityWalletMapper.selectValue1Rankings(ACTIVITY_ID, 50);
			setDefaultAvatar(list);
			redisUtil.set(RedisConstans.putRediskey(RedisConstans.RANKING, ACTIVITY_ID, 0), list, RedisConstans.ONE_DAY);
			//
			String property0 = "";
			String property1 = "";
			if(!CollectionUtils.isEmpty(list2)){
				UserVo userVo = list2.get(0);
				property0 = JSON.toJSONString(userVo);
			}
			if(!CollectionUtils.isEmpty(list)){
				UserVo userVo = list.get(0);
				property1 = JSON.toJSONString(userVo);
			}
			ActivityData data = new ActivityData();
			data.setProperty0(property0);
			data.setProperty1(property1);
			activityDataMapper.update(data, new LambdaQueryWrapper<ActivityData>().eq(ActivityData::getActivityId, ACTIVITY_ID));
			redisUtil.del(RedisConstans.SIGN_SHOW);
			return null;
		} else if(type == 0){
			List<UserVo> list = activityWalletMapper.selectValue1Rankings(ACTIVITY_ID, 50);
			setDefaultAvatar(list);
			redisUtil.set(RedisConstans.putRediskey(RedisConstans.RANKING, ACTIVITY_ID, type), list, RedisConstans.ONE_DAY);
			return list;
		} else {
			List<UserVo> list = activityWalletMapper.selectValue2Rankings(ACTIVITY_ID, 50);
			setDefaultAvatar(list);
			redisUtil.set(RedisConstans.putRediskey(RedisConstans.RANKING, ACTIVITY_ID, type), list, RedisConstans.ONE_DAY);
			return list;
		}
	}

	private void setDefaultAvatar(List<UserVo> list){
		for (UserVo userVo : list) {
			if(StringUtils.isBlank(userVo.getAvatarUrl())){
				userVo.setAvatarUrl(Constants.DEFAULT_AVATAR);
			}
		}
	}

	private ActivityWallet getWalletInfo(String userId){
		String key = RedisConstans.putRediskey(RedisConstans.WALLET, ACTIVITY_ID, userId);
		ActivityWallet wallet = redisUtil.get(key);
		if(wallet != null){
			return wallet;
		}
		LambdaQueryWrapper< ActivityWallet> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(ActivityWallet::getActivityId, ACTIVITY_ID).eq(ActivityWallet::getUserId, userId);
		wallet = activityWalletMapper.selectOne(wrapper);
		if (wallet == null) {
			wallet = new ActivityWallet();
			wallet.setUserId(userId);
			wallet.setAmount1(0);
			wallet.setAmount2(0);
		}
		redisUtil.set(key, wallet, RedisConstans.ONE_HOUR);
		return wallet;
	}

	@Override
	public Map<String, Object> rankings(String userId, Integer type) {
		if(type == null ){
			throw new ServiceException("类型不能为空");
		}
		Map<String, Object> result = new HashMap<>();
		//排行榜
		List<UserVo> list = redisUtil.get(RedisConstans.WEEK_SWEET_RANKING + ACTIVITY_ID);
		if(CollectionUtils.isEmpty(list)){
			list = getRankingsByDb(type);
		}
		int rank = 1;
		int previousValue = 0;
		UserVo userVo = new UserVo();
		for (UserVo vo : list) {
			vo.setRank(rank);
			vo.setAvatarUrl(StringUtils.isBlank(vo.getAvatarUrl()) ? Constants.DEFAULT_AVATAR : vo.getAvatarUrl());
			if(userId.equals(vo.getUserId())){
				userVo.setRank(rank);
				if(rank != 1){
					userVo.setDiffValue(previousValue - vo.getValue());
					if(userVo.getDiffValue() == 0){
						userVo.setDiffValue(1);
					}
				}
			}
			previousValue = vo.getValue();
			rank++;
		}
		//个人信息
		User user = userService.getUser(userId);
		ActivityWallet wallet = getWalletInfo(userId);
		userVo.setUserId(user.getUserId())
				.setAccountId(user.getAccountId())
				.setNickname(user.getNickname())
				.setAvatarUrl(StringUtils.isBlank(user.getAvatarUrl()) ? Constants.DEFAULT_AVATAR : user.getAvatarUrl())
				//若在对应榜单上则显示实际名次“1-50”距上一名还差xxx；若未上榜则显示“未上榜”，距上榜还差xxx。
				.setValue(type == 0 ? wallet.getAmount1() : wallet.getAmount2());
		if(userVo.getRank() == null){
			userVo.setRank(-1);
		}
		if(userVo.getDiffValue() == null){
			userVo.setDiffValue(previousValue - (wallet == null ? 0 : type == 0 ? wallet.getAmount1() : wallet.getAmount2()));
		}
		//返回
		result.put("ranking", list);
		result.put("self", userVo);
		return result;
	}

	@Override
	public Map<String, Object> task(String userId) {
		Map<String, Object> result = new HashMap<>();
		//个人信息
		User user = userService.getUser(userId);
		ActivityWallet wallet = getWalletInfo(userId);
		//任务列表
		List<TaskVo> list = new ArrayList<>();
		Integer current = 0;
		if(wallet.getAmount1() >= 100000 || wallet.getAmount2() >= 100000){
			list.add(new TaskVo(1, "10W"));
		} else {
			list.add(new TaskVo(0, "10W"));
		}
		if(wallet.getAmount1() >= 500000 || wallet.getAmount2() >= 500000){
			list.add(new TaskVo(1, "50W"));
			current = 1;
		} else {
			list.add(new TaskVo(0, "50W"));
		}
		if(wallet.getAmount1() >= 990000 || wallet.getAmount2() >= 990000){
			list.add(new TaskVo(1, "99W"));
			current = 2;
		} else {
			list.add(new TaskVo(0, "99W"));
		}
		if(wallet.getAmount1() >= 2000000 || wallet.getAmount2() >= 2000000){
			list.add(new TaskVo(1, "200W"));
			current = 3;
		} else {
			list.add(new TaskVo(0, "200W"));
		}
		if(wallet.getAmount1() >= 3000000 || wallet.getAmount2() >= 3000000){
			list.add(new TaskVo(1, "300W"));
			current = 4;
		} else {
			list.add(new TaskVo(0, "300W"));
		}
		if(wallet.getAmount1() >= 5000000 || wallet.getAmount2() >= 5000000){
			list.add(new TaskVo(1, "500W"));
			current = 5;
		} else {
			list.add(new TaskVo(0, "500W"));
		}
		//返回
		result.put("userId", user.getUserId());
		result.put("accountId", user.getAccountId());
		result.put("nickname", user.getNickname());
		result.put("avatarUrl", StringUtils.isBlank(user.getAvatarUrl()) ? Constants.DEFAULT_AVATAR : user.getAvatarUrl());
		result.put("value", wallet.getAmount1());
		result.put("targetValue", wallet.getAmount2());
		result.put("taskList", list);
		result.put("current", current);
		return result;
	}

	@Override
	public List<Map<String, Object>> starShow() {
		Integer endActivityId = ACTIVITY_ID - 1;
		Activity activity = activityService.getActivity(ACTIVITY_ID);
		if(activity.getEndTime().isBefore(LocalDateTime.now())){
			endActivityId = ACTIVITY_ID;
			redisUtil.del(RedisConstans.SIGN_SHOW);
		}
		List<Map<String, Object>> resultList = redisUtil.get(RedisConstans.SIGN_SHOW);
		if(!CollectionUtils.isEmpty(resultList)){
			return resultList;
		}
		resultList = new ArrayList<>();
		LambdaQueryWrapper<ActivityData> wrapper = new LambdaQueryWrapper<>();
		wrapper.ge(ActivityData::getActivityId, 15).le(ActivityData::getActivityId, 26).orderByAsc(ActivityData::getActivityId);
		List<ActivityData> list = activityDataMapper.selectList(wrapper);
		int num = 15;
		for (ActivityData activityData : list) {
			Map<String, Object> map = new HashMap<>();
			map.put("flag", 0);
			if(StringUtils.isNotBlank(activityData.getProperty0()) && num <= endActivityId){
				map.put("master", JSON.parseObject(activityData.getProperty0()));
				map.put("flag", 1);
			}
			if(StringUtils.isNotBlank(activityData.getProperty1()) && num <= endActivityId){
				map.put("slave", JSON.parseObject(activityData.getProperty1()));
			}
			map.put("signName", activityData.getContent());
			resultList.add(map);
			num++;
		}
		redisUtil.set(RedisConstans.SIGN_SHOW, resultList, RedisConstans.ONE_HOUR);
		return resultList;
	}


	@Override
	public void givePrize() {
		List<ActivityPrize> prizeList = getPrize(2);
		if(CollectionUtils.isEmpty(prizeList)){
			return;
		}
		List<UserVo> rankingList = getRankingsByDb(0);
		if(rankingList.size() >= 1){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 101).collect(Collectors.toList()).get(0);
			List<UserVo> list = rankingList.subList(0, 1);
			savePrize2(prize1, list.get(0).getUserId());
		}
		if(rankingList.size() >= 3){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 102).collect(Collectors.toList()).get(0);
			List<UserVo> list = rankingList.subList(1, 3);
			for (UserVo userVo : list) {
				savePrize2(prize1, userVo.getUserId());
			}
		}
		if(rankingList.size() >= 10){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 103).collect(Collectors.toList()).get(0);
			List<UserVo> list = rankingList.subList(3, 10);
			for (UserVo userVo : list) {
				savePrize2(prize1, userVo.getUserId());
			}
		}
		List<UserVo> rankingList2 = getRankingsByDb(1);
		if(rankingList2.size() >= 1){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 101).collect(Collectors.toList()).get(0);
			List<UserVo> list = rankingList2.subList(0, 1);
			savePrize2(prize1, list.get(0).getUserId());
		}
		if(rankingList2.size() >= 3){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 102).collect(Collectors.toList()).get(0);
			List<UserVo> list = rankingList2.subList(1, 3);
			for (UserVo userVo : list) {
				savePrize2(prize1, userVo.getUserId());
			}
		}
		if(rankingList2.size() >= 10){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 103).collect(Collectors.toList()).get(0);
			List<UserVo> list = rankingList2.subList(3, 10);
			for (UserVo userVo : list) {
				savePrize2(prize1, userVo.getUserId());
			}
		}
	}


	//发放奖励
	@Override
	public void giveReward(String userId, long totalValue, List<ActivityPrize> prizeList){
		if(totalValue >= 100000){
			ActivityPrize prize = prizeList.stream().filter(p -> p.getType() == 11).collect(Collectors.toList()).get(0);
			savePrize(prize, userId);
		}
		if(totalValue >= 500000){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 21).collect(Collectors.toList()).get(0);
			savePrize(prize1, userId);
			ActivityPrize prize2 = prizeList.stream().filter(p -> p.getType() == 22).collect(Collectors.toList()).get(0);
			savePrize(prize2, userId);
		}
		if(totalValue >= 990000){
			ActivityPrize prize = prizeList.stream().filter(p -> p.getType() == 31).collect(Collectors.toList()).get(0);
			savePrize(prize, userId);
			ActivityPrize prize2 = prizeList.stream().filter(p -> p.getType() == 32).collect(Collectors.toList()).get(0);
			savePrize(prize2, userId);
		}
		if(totalValue >= 2000000){
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 41).collect(Collectors.toList()).get(0);
			savePrize(prize1, userId);
			ActivityPrize prize2 = prizeList.stream().filter(p -> p.getType() == 42).collect(Collectors.toList()).get(0);
			savePrize(prize2, userId);
		}
		if(totalValue >= 3000000) {
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 51).collect(Collectors.toList()).get(0);
			savePrize(prize1, userId);
			ActivityPrize prize2 = prizeList.stream().filter(p -> p.getType() == 52).collect(Collectors.toList()).get(0);
			savePrize(prize2, userId);
		}
		if(totalValue >= 5000000) {
			ActivityPrize prize1 = prizeList.stream().filter(p -> p.getType() == 61).collect(Collectors.toList()).get(0);
			savePrize(prize1, userId);
		}
	}

	//保存奖品
	public void savePrize(ActivityPrize prize, String userId){
		Integer prizeType = prize.getType();
		String key = RedisConstans.putRediskey(RedisConstans.PRIZE_RECORD, ACTIVITY_ID, prizeType, userId);
		if(redisUtil.get(key) != null){
			return;
		}

		/*LambdaQueryWrapper<ActivityRecord> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(ActivityRecord::getActivityId, ACTIVITY_ID).eq(ActivityRecord::getUserId, userId).eq(ActivityRecord::getGiftId, prize.getGiftId()).in(ActivityRecord::getType, 1, 2).last("limit 1");
		ActivityRecord activityRecord = activityRecordMapper.selectOne(wrapper);
		if (activityRecord != null) {
			return;
		}*/

		if(prize.getSource() == 2){
			giftService.saveUserDress(ACTIVITY_ID, userId, prize.getGiftId(), 2, prize.getNum(), "星座物语-巨蟹座获得");
		} else {
			giftService.savePrize(ACTIVITY_ID, userId, prize.getGiftId(), 1, prize.getNum());
		}
		redisUtil.set(key, 1, RedisConstans.TWO_MONTH);
	}


	//保存奖品
	public void savePrize2(ActivityPrize prize, String userId){
		if(prize.getSource() == 2){
			giftService.saveUserDress(ACTIVITY_ID, userId, prize.getGiftId(), 2, prize.getNum(), "星座物语-巨蟹座获得");
		} else {
			giftService.savePrize(ACTIVITY_ID, userId, prize.getGiftId(), 1, prize.getNum());
		}
	}
}
